<?php

/** Networking related functions and classes
 *
 *  This collection of functions (libary) is licensed under GPL2.
 *  See LICENSE or www.gnu.org for more details.
 *  @author Jyry Kuukkanen
 *  @copyright Jyry Kuukkanen
 */

include_once("sostring.php");
include_once("sodebug.php");

/* Compression methods */
define(SOCM_GZIP, "gzip");

/** Returns the web browser name.
 *  @return string The web browser name. This is an extract from the
 *  environment string send by each browser. e.g. Netscape are always
 *  recognized as 'mozilla' as its html engine is called mozilla. So check
 *  the version to recognise the browser properly. Other browsers:
 *  'msie'      M$-exploder
 *  'konqueror' KDE's Konqueror
 *  'mozilla"   Netscape & Mozilla
 *  For the others you must do some debuging XXX ??? Henkka: fix this comment
 *  @package sogeneric
 */
function soGetBrowser() {
    $env = soCaseConv(getenv("HTTP_USER_AGENT"), "L");
    $env = soSwapStr($env, " ", "/", 1);
    $result = soExtractVal($env, "/", 1);

    return $result;
} // soGetBrowser()


/** Reuturns the web browser version.
 *  Example: Mozilla returns 5 as its version number because of it's engine ver
 *  @return string The browser version.
 *  @package sogeneric
 */
function soGetBrowserVersion() {
    $env = soCaseConv(getenv("HTTP_USER_AGENT"), "L");
    $env = soSwapStr($env, " ", "/", 1);
    /* The version number success the first slash */
    $ind = soLocateStr($env, "/", 1);

    return $env[$ind+1];
} // soGetBrowserVersion()


/** Returns HTML code that will redirect the browse to other address.
 *  @param string $Addr URL to jump to
 *  @param int $Delay Time in seconds how long wait before jumping to URL
 *  @param string $Msg Message to display while pausing
 *  @param string $Title Page title
 *  @package sogeneric
 */
function soGetRedirHtml($Url, $Delay = 0, $Msg, $Title = "Redirecting") {
    $result = "<HTML><HEAD>\n";
    $result .= "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"$Delay; URL=$Url\">\n";
    $result .= "<TITLE>$Title</TITLE></HEAD><BODY>\n";
    $result .= "$Msg\n";
    $result .= "</BODY></HTML>\n";
    return $result;
}; // soGetRedirHtml


/** Check whether client supports specified compression
 *  Most browsers support compressed data. This function check if specified
 *      compression method is supported.
 *  @param string $Method Compressions method name (gzip, x-gzip)
 *  @param bool True(1) if specified method is supported by the client,
 *      otherwise returns false(0).
 */
function soCheckClientCompression($Method) {
    return in_array($Method, soGetClientCompressions());
}; // soCheckClientCompression


/** Returns an array of compressions supported by the client.
 *  Most browsers support compressed data. This function returns an array of
 *      supported compression names or en empty array when not supported at all
 *  @param array Compression names or en empty array
 */
function soGetClientCompressions() {
    $compressions = array("gzip", "x-gzip", "deflate");
    $result = array();

    foreach ($compressions as $name) {
        if (ereg($name, $_SERVER["HTTP_ACCEPT_ENCODING"])) $result[] = $name;
    }; // foreach

    return $result;
}; // soGetClientCompressions


/** Class to handle output buffering.
 *  The purpose of this class is to offer simple methods to start capturing
 *  all data going to the client and then outputing it in compressed format,
 *  if the compression if supported by the client.
 *  @var bool $Capturing When set, all output to the client is beeing captured
 */
class soOutputBuffer {
    var $Capturing = 0;

    /** Constructor
     *  @param bool $Start When set, causes calling of startCapture right
     *      after construction of object.
     */
    function soOutputBuffer($Start = 0) {
        if ($Start) $this->startCapture();
    } // soOutputBuffer


    /** Starts capturing all output to buffer.
     *  N.B. Buffer is cleared!
     */
    function startCapture() {
        ob_end_clean();
        ob_start();
        ob_implicit_flush(0);
    } // startCapture


    /** Stops capturing and returns buffer.
     *  @var bool $Print When set, sends captured data to the client.
     *  @Compress int One of the following: 0=leave the captured data as is,
     *      1=sort out best compression method if any and compress, 2=use
     *      gzip to compress
     */
    function finishCapture($Print, $Compress = 0) {
        $result = ob_get_contents();
        ob_end_clean();

        /* Debugging? */
        global $soDebugLevel;
        if ($soDebugLevel > SOD_DET) {
            soDebug("soOutputBuffer->finishCapture: $result", SOD_DET);
        };

        /* Compress is requested so */
        switch ($Compress) {
            case 1:
                if (soCheckClientCompression(SOCM_GZIP)) {
                    $result = $this->__compress($result, SOCM_GZIP);
                };
                break;
            case 2:
                $result = $this->__compress($result, SOCM_GZIP);
                break;
        }; // switch

        if ($Print) echo $result;

        $this->Capturing = 0;
        return $result;
    } // finishCapture


    /** Compresses gived string so it can be sent to the client.
     *  @param string $Data Data to be send to the client.
     *  @param SOCM_* $Method Compression method. See SOCM_* defines for more.
     *  @return string Compressed data with headers etc.
     */
    function __compress($Data, $Method = SOCM_GZIP) {
        switch ($Method) {
            case SOCM_GZIP:
                $size = strlen($Data);
                $crc = crc32($Data);
                $Data = gzcompress($Data);
                $result = header("Content-Encoding: gzip").
                          "\x1f\x8b\x08\x00\x00\x00\x00\x00".
                          $Data;
        }; // switch

        return $result;
    } // __compress

}; // soOutputBuffer


/** Calls a URL and returns the result.
 *  @param string $Url Url to call
 *  @return string Url call result.
 */
function soCallUrl($Url) {
    $uh = curl_init($pageSpec);
    curl_setopt($uh, CURLOPT_RETURNTRANSFER, 1);
    $result = curl_exec($uh);
    curl_close ($uh);
    /* if you intend to print this page, better clear out expiration tag */
    #$result = preg_replace('/(?s)<meta http-equiv="Expires"[^>]*>/i',
    #           '', $result);

    return $result;
}; // soCallUrl


/** Authentification login prompt.
 *  @param array/string $Users Array that contains usernames as key and
 *      passwords as value: $Users["user"] = "passwd";
 *  @param string EntryMsg Message to display in the prompt
 *  @param string ErrorMsg Message to display in bad login attempt
 *  @return bool Returns true. On bad login, prints another logint prompt.
 */
function soAuthLogin($Users, $EntryMsg, $ErrorMsg) {
    $_user = $_SERVER["PHP_AUTH_USER"];
    $_passwd = $_SERVER["PHP_AUTH_PW"];
    $_type = $_SERVER["PHP_AUTH_TYPE"];
    
    if (!isset($_user)) {

        // If empty, send header causing dialog box to appear
        __soAuthLoginPrompt($EntryMsg, $ErrorMsg, "");
        exit;
    } else {

        $keys = array_keys($Users);
        if (in_array($_user, $keys)) {
            $passwd = $Users[$_user];
        } else {
            $passwd = NULL;
        };
        if (($pos < 0) || ($_passwd != $passwd)) {
            __soAuthLoginPrompt($EntryMsg,
                                $ErrorMsg."/".$pos."/".$Users[$pos]);
            exit;
        };

    }

    return 1;
}; // soAuthLogin


/** Prints the authentication login prompt
 *  @param string EntryMsg Message to display in the prompt
 *  @param string ErrorMsg Message to display in bad login attempt
 */
function __soAuthLoginPrompt($EntryMsg, $ErrorMsg) {
    header('WWW-Authenticate: Basic realm="'.$EntryMsg.'"');
    header('HTTP/1.0 401 Unauthorized');
    echo $ErrorMsg;
}; // __soAuthLoginPrompt



/** HTTP(s) requester for POST and GET methods.
 *  Example: soHttpRequest("localhost", "/", "POST", array("abc" => 123));
 *  Example: soHttpRequest("localhost", "/", "GET", array("abc" => 123), 1);
 *  @param string $Host Host to connect to
 *  @param string $Path Path to host file, e.g. /path/to/this.html
 *  @param string $Method Either "GET" or "POST" (incase-sensitive)
 *  @param array $Vars Associative array or var names & values
 *  @param bool $Ssl When set, tries HTTPS connection instead of HTTP
 *  @return string Request result.
 */
function soHttpRequest($Host, $Path, $Method, $Vars, $Ssl = 0) {

    $Method = strtoupper($Method);
    if ($Ssl) {
        $Method = "ssl://".$Method;
        $Port = 80;
    } else {
        $Port = 443;
    }; // else if

    $fp = fsockopen($Host, $Port);

    $data = "";
    foreach ($Vars as $key => $value) {
        $data = soJoinStr($data, "&", $key."=".$value, 1);
    }; // foreach

    if ($Method == "GET") $Path .= "?" . $data;

    fputs($fp, $Method." ".$Path." HTTP/1.1\r\n");
    fputs($fp, "Host: ".$host."\r\n");
    if ($Method == 'POST') {
      fputs($fp,"Content-type: application/x-www-form-urlencoded\r\n");
      fputs($fp, "Content-length: ".strlen($data)."\r\n");
    };
    fputs($fp, "Connection: close\r\n\r\n");
    if ($Method == "POST") fputs($fp, $data);

    while (!feof($fp)) $buf .= fgets($fp,128);

    fclose($fp);
    return $buf;
}; // soHttpRequest


/** Returns OS environment variable
 *  Apparently getenv() does not return things like HOSTNAME etc.
 *  @param string Environment variable name
 *  @return string Environment variable value (empty when variable is not set)
 */
function soGetEnv($Name) {
    $result = '';
    $ph = popen('echo $'.$Name, 'r');
    while ($ph && ($data = fread($ph, 64))) $result .= $data;
    if ($ph) pclose($ph);

    return trim($result);
};

?>
